package net.aiion.weave.impl.bytecode;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * This class is an performance-optimized, unsynchronized (thus not thread-safe) and reusable implementation variant of
 * {@link ByteArrayOutputStream}.
 * 
 * @author Stefan Braune
 */
public class BytecodeStream extends OutputStream
{
    private byte[] buf;
    private int count;

    public BytecodeStream() {
        this(512);
    }

    public BytecodeStream(final int aSize) {
        buf = new byte[aSize];
    }

    private void ensureCapacity(int minCapacity) {
        if (buf.length >= minCapacity) {
            return;
        }

        final int oldCapacity = buf.length;
        int newCapacity = oldCapacity << 1;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }

        final byte[] tmp = new byte[newCapacity];
        System.arraycopy(buf, 0, tmp, 0, oldCapacity);
        buf = tmp;
    }

    @Override
    public void write(final int b) throws IOException {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count++;
    }

    @Override
    public void write(byte[] b) throws IOException {
        write(b, 0, b.length);
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        if (off < 0 || off > b.length || len < 0 || off + len > b.length) {
            throw new IndexOutOfBoundsException();
        }

        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

    public byte[] getBytes() {
        final byte[] tmp = new byte[count];
        System.arraycopy(buf, 0, tmp, 0, count);
        return tmp;
    }

    public int size() {
        return count;
    }

    public void reset() {
        count = 0;
    }

    @Override
    public void flush() throws IOException {
    }

    @Override
    public void close() {
    }
}
